package edu.gatech.gro;

import java.util.ArrayList;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import edu.gatech.gro.http.IResponseAdapter;
import edu.gatech.gro.model.ObjectResponse;
import edu.gatech.gro.model.User;

public class UserDisplayActivity extends Activity {

	private static final String TAG = "USER_EDIT_ACTIVITY";

	private final IncomingHandler mHandler = new IncomingHandler();

	private static final int GOT_USERS = 0;
	private static final int GOT_LOGGED = 1;
	private static final int FAILED_TO_LOG = 2;

	private static final int USER_CREATED = 10;
	private static final int USER_UPDATED = 11;
	private static final int USER_DELETED = 12;

	private static final int AFTER_LOGIN_LIST = 20;
	private static final int AFTER_LOGIN_EDIT = 21;
	private static final int AFTER_LOGIN_DELETE = 22;

	private static GroceryListManagerApplication app;

	private Button mAddUserButton;
	private ListView mUserList;
	private UserAdapter mUserAdapter;

	private AlertDialog mAlertDialog;
	private ProgressDialog mProgressUser;
	private ProgressDialog mProgressDelete;
	private ProgressDialog mProgressLogin;
	private ProgressDialog mProgressSynchronization;

	private int mDoAfterLogin = 0;
	private User mCurrentUser;
	private boolean mCurrentPasswordOk = false;

	private ArrayList<User> mCurrentUsers;
	private User mLastUserDeleted;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		app = (GroceryListManagerApplication) getApplicationContext();

		setContentView(R.layout.user_manager);

		mAlertDialog = new AlertDialog.Builder(UserDisplayActivity.this).create();
		mAlertDialog.setButton("OK", new DialogInterface.OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
				dialog.dismiss();
			}
		});

		mAddUserButton = (Button) findViewById(R.id.addUserButton);
		mUserList = (ListView) findViewById(R.id.userList);

		mAddUserButton.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				Log.d(TAG, "mAddUserButton clicked");
				mCurrentUser = null;
				displayUserAdderPanel();
			}
		});

	}

	@Override
	public void onResume() {
		super.onResume();
		Log.d(TAG, "Resume");
		waitForSynchronization();
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

		switch (requestCode) {
			case USER_UPDATED:
				if (resultCode == RESULT_OK) {
					Bundle b = data.getExtras();
					updateUserAfterEdit(b.getString("username"), b.getString("email"));
				}
				break;
		}
	}

	private void updateUserAfterEdit(String username, String email) {
		mCurrentUser.setUsername(username);
		mCurrentUser.setEmail(email);
		mUserAdapter.notifyDataSetChanged();
	}

	private void waitForSynchronization() {
		if (mProgressSynchronization == null || !mProgressSynchronization.isShowing()) {
			mProgressSynchronization = ProgressDialog.show(UserDisplayActivity.this, "", this.getString(R.string.progressSynchronization), true, false);
			app.synchronize(mSynchronizationListener);
		}
	}

	private void waitForUserList() {
		if (mProgressUser == null || !mProgressUser.isShowing()) {
			mProgressUser = ProgressDialog.show(UserDisplayActivity.this, "", this.getString(R.string.progressUserList), true, false);
			app.getAllUsers(mUsersListener);
		}
	}

	private void waitForLogin(String username, String password) {
		if (mProgressLogin == null || !mProgressLogin.isShowing()) {
			mProgressLogin = ProgressDialog.show(UserDisplayActivity.this, "", this.getString(R.string.progressLogin), true, false);
			app.login(username, password, mLoginListener);
		}
	}

	private void waitForDelete() {
		if (mProgressDelete == null || !mProgressDelete.isShowing()) {
			mLastUserDeleted = mCurrentUser;
			mProgressDelete = ProgressDialog.show(UserDisplayActivity.this, "", this.getString(R.string.progressUserDelete), true, false);
			app.deleteUser(mCurrentUser, mDeleteListener);
		}
	}

	private void refreshUserList() {
		if (mCurrentUsers != null && mCurrentUsers.size() > 0) {
			mUserAdapter = new UserAdapter(UserDisplayActivity.this, R.layout.user_list_item, mCurrentUsers);
			mUserList.setAdapter(mUserAdapter);
		}
	}

	private void displayUserAdderPanel() {
		Intent i = new Intent(this, UserEditActivity.class);
		i.putExtra("hasUser", mCurrentUser != null);
		if (mCurrentUser == null) {
			startActivityForResult(i, USER_CREATED);
		} else {
			i.putExtra("userId", mCurrentUser.getId());
			i.putExtra("username", mCurrentUser.getUsername());
			i.putExtra("email", mCurrentUser.getEmail());
			startActivityForResult(i, USER_UPDATED);
		}
	}

	private void displayNamedLists(final User user) {
		if (loginRequired(user)) {
			mDoAfterLogin = AFTER_LOGIN_LIST;
			promptLogin(user);
		} else if (mCurrentPasswordOk) {
			mCurrentUser = user;
			Intent i = new Intent(this, NamedListDisplayActivity.class);
			i.putExtra("userId", mCurrentUser.getId());
			startActivity(i);
		}
	}

	private void editUser(final User user) {
		if (loginRequired(user)) {
			mDoAfterLogin = AFTER_LOGIN_EDIT;
			promptLogin(user);
		} else if (mCurrentPasswordOk) {
			mCurrentUser = user;
			displayUserAdderPanel();
		}
	}

	private void deleteUser(final User user) {
		if (loginRequired(user)) {
			mDoAfterLogin = AFTER_LOGIN_DELETE;
			promptLogin(user);
		} else if (mCurrentPasswordOk) {
			mCurrentUser = user;
			waitForDelete();
		}
	}

	private boolean loginRequired(final User user) {
		return mCurrentUser == null || user.getId() != mCurrentUser.getId() || !mCurrentPasswordOk;
	}

	private void promptLogin(final User user) {
		mCurrentUser = null;
		mCurrentPasswordOk = false;

		LayoutInflater factory = LayoutInflater.from(this);
		final View textEntryView = factory.inflate(R.layout.login_password, null);
		AlertDialog.Builder alert = new AlertDialog.Builder(this);
		alert.setTitle("Login");
		alert.setMessage(R.string.loginEnterPasswordLabel);
		alert.setView(textEntryView);

		alert.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int whichButton) {
				EditText mPassword = (EditText) textEntryView.findViewById(R.id.loginPasswordText);
				String password = mPassword.getText().toString();
				Log.d(TAG, "Password: " + password);

				waitForLogin(user.getUsername(), password);
			}
		});

		alert.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
			}
		});
		alert.show();
	}

	private void promptAvailableActions(final User user) {
		String[] items = new String[2];
		items[0] = this.getString(R.string.edit);
		items[1] = this.getString(R.string.delete);
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle(R.string.whattodo);
		builder.setItems(items, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int item) {
				switch (item) {
					case 0: // Edit
						editUser(user);
						break;
					case 1: // Delete
						deleteUser(user);
						break;
				}
			}
		});
		AlertDialog alert = builder.create();
		alert.show();
	}

	/**
	 * Helper function to dismiss a progress dialog
	 * 
	 * @param theProgress
	 *          the progress dialog to dismiss
	 */
	private void dismissProgress(ProgressDialog theProgress) {
		if (theProgress != null && theProgress.isShowing()) {
			theProgress.dismiss();
		}
	}

	private User getUser(int id) {
		for (User u : mCurrentUsers) {
			if (u.getId() == id) {
				return u;
			}
		}
		return null;
	}

	private final IResponseAdapter mSynchronizationListener = new IResponseAdapter() {

		@Override
		public void onResponse(ObjectResponse response) {
			Log.d(TAG, "Synchronization completed.");
			dismissProgress(mProgressSynchronization);
			waitForUserList();
		}
	};

	private final IResponseAdapter mUsersListener = new IResponseAdapter() {

		@Override
		public void onResponse(ObjectResponse response) {
			dismissProgress(mProgressUser);
			if (response.isSuccessful()) {
				// Save the current list of users
				mCurrentUsers = (ArrayList<User>) response.getData();
				Log.d(TAG, "Users received!");

				// Send a message to the activity to update the view (on the UI thread)
				mHandler.sendEmptyMessage(GOT_USERS);
			} else {
				displayError(R.string.failRetrieveUsersTitle, response.getErrorsAsString());
			}
		}

	};

	private final IResponseAdapter mLoginListener = new IResponseAdapter() {

		@Override
		public void onResponse(ObjectResponse response) {
			dismissProgress(mProgressLogin);
			mCurrentPasswordOk = response.isSuccessful();
			if (response.isSuccessful()) {
				User cUser = (User) response.getData();
				mCurrentUser = getUser(cUser.getId());
				mCurrentUser.setUsername(cUser.getUsername());
				mCurrentUser.setEmail(cUser.getEmail());
				mHandler.sendEmptyMessage(GOT_LOGGED);
			} else {
				mHandler.sendEmptyMessage(FAILED_TO_LOG);
			}
		}
	};

	private final IResponseAdapter mDeleteListener = new IResponseAdapter() {

		@Override
		public void onResponse(ObjectResponse response) {
			dismissProgress(mProgressDelete);
			if (response.isSuccessful()) {
				mHandler.sendEmptyMessage(USER_DELETED);
			} else {
				mLastUserDeleted = null;
			}
		}
	};

	/**
	 * Handler of incoming messages from the Service
	 */
	private class IncomingHandler extends Handler {

		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
				case GOT_USERS:
					refreshUserList();
					break;
				case GOT_LOGGED:
					switch (mDoAfterLogin) {
						case AFTER_LOGIN_DELETE:
							deleteUser(mCurrentUser);
							break;
						case AFTER_LOGIN_EDIT:
							editUser(mCurrentUser);
							break;
						case AFTER_LOGIN_LIST:
							displayNamedLists(mCurrentUser);
							break;
					}
					break;
				case FAILED_TO_LOG:
					userFailedLog();
					break;
				case USER_DELETED:
					userDeleted();
					break;
				default:
					super.handleMessage(msg);
					break;
			}
		}
	}

	private void userFailedLog() {
		displayError(R.string.errorLoginTitle, R.string.errorLoginMessage);
	}

	private void userDeleted() {
		if (mLastUserDeleted != null) {
			mCurrentUsers.remove(mLastUserDeleted);
			mUserAdapter.notifyDataSetChanged();
			mLastUserDeleted = null;
			mCurrentUser = null;
		}
	}

	private void displayError(final int titleId, final int messageId) {
		mAlertDialog.setTitle(titleId);
		mAlertDialog.setMessage(this.getString(messageId));
		mAlertDialog.show();
	}

	private void displayError(final int titleId, final String message) {
		mAlertDialog.setTitle(titleId);
		mAlertDialog.setMessage(message);
		mAlertDialog.show();
	}

	private class UserAdapter extends ArrayAdapter<User> {

		private static final String TAG = "USER_ADAPTER";

		private final ArrayList<User> mItems;

		public UserAdapter(Context context, int textViewResourceId, ArrayList<User> items) {
			super(context, textViewResourceId, items);
			this.mItems = items;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View v = convertView;
			if (v == null) {
				LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
				v = vi.inflate(R.layout.user_list_item, null);
			}
			final User u = mItems.get(position);
			if (u != null) {
				TextView tt = (TextView) v.findViewById(R.id.user_item_line1);
				TextView bt = (TextView) v.findViewById(R.id.user_item_line2);
				if (tt != null) {
					tt.setText(u.getUsername());
				}
				if (bt != null) {
					// bt.setText(u.getEmail());
				}
				tt.setOnClickListener(new View.OnClickListener() {

					@Override
					public void onClick(View v) {
						Log.d(TAG, "user #" + u.getId() + " clicked!");
						displayNamedLists(u);
					}
				});
				tt.setOnLongClickListener(new View.OnLongClickListener() {

					@Override
					public boolean onLongClick(View v) {
						Log.d(TAG, "Long click on user #" + u.getId());
						promptAvailableActions(u);
						return true;
					}
				});
			}
			return v;
		}
	}
}
